package demo4;

import java.util.*;

class PCB {
    String name;
    int arrivalTime;     // 到达时间
    int burstTime;       // 服务时间
    int finishedTime = 0; // 完成时间
    int runnedTime = 0;   // 已运行时间（用于RR）

    public PCB(String name, int arrivalTime, int burstTime) {
        this.name = name;
        this.arrivalTime = arrivalTime;
        this.burstTime = burstTime;
    }

    int getTurnaroundTime() {
        return finishedTime - arrivalTime;
    }

    double getWeightedTurnaroundTime() {
        return (double) getTurnaroundTime() / burstTime;
    }

    public PCB copy() {
        return new PCB(name, arrivalTime, burstTime);
    }
}

public class ProcessScheduler {
    static int timeSlice = 2; // 时间片长度

    public static void main(String[] args) {
        List<PCB> base = Arrays.asList(
                new PCB("P1", 0, 3),
                new PCB("P2", 2, 6),
                new PCB("P3", 4, 4),
                new PCB("P4", 6, 5),
                new PCB("P5", 8, 2)
        );

        // 三种调度算法依次执行
        fcfs(copyList(base));
        sjf(copyList(base));
        rr(copyList(base));
    }

    static List<PCB> copyList(List<PCB> origin) {
        List<PCB> copy = new ArrayList<>();
        for (PCB p : origin) copy.add(p.copy());
        return copy;
    }

    // 1️⃣ FCFS：先来先服务（按到达时间顺序执行）
    static void fcfs(List<PCB> processes) {
        // 按到达时间排序
        processes.sort(Comparator.comparingInt(p -> p.arrivalTime));
        int time = 0; // 当前时间

        for (PCB p : processes) {
            // 如果该进程还没到达，时间快进
            if (time < p.arrivalTime) time = p.arrivalTime;

            // 执行当前进程，耗时 burstTime
            time += p.burstTime;

            // 记录完成时间
            p.finishedTime = time;
        }

        printResult("FCFS", processes);
    }

    // 2️⃣ SJF：短作业优先（非抢占式，每次选服务时间最短的）
    static void sjf(List<PCB> processes) {
        List<PCB> pending = new ArrayList<>(processes); // 所有未执行进程
        List<PCB> done = new ArrayList<>();
        int time = 0;

        while (!pending.isEmpty()) {
            List<PCB> ready = new ArrayList<>();

            // 找出当前时间已到达的进程
            for (PCB p : pending) {
                if (p.arrivalTime <= time) ready.add(p);
            }

            // 没有可执行的进程，时间+1等待
            if (ready.isEmpty()) {
                time++;
                continue;
            }

            // 从就绪队列中选择服务时间最短的一个
            ready.sort(Comparator.comparingInt(p -> p.burstTime));
            PCB shortest = ready.get(0);

            // 执行并更新时间
            time += shortest.burstTime;
            shortest.finishedTime = time;

            // 从等待队列移除，标记已完成
            pending.remove(shortest);
            done.add(shortest);
        }

        printResult("SJF", processes);
    }

    // 3️⃣ RR：时间片轮转
    static void rr(List<PCB> processes) {
        List<PCB> pending = new ArrayList<>(processes); // 未到达的进程
        List<PCB> queue = new ArrayList<>();            // 就绪队列
        int time = 0;                                    // 当前时间

        while (!queue.isEmpty() || !pending.isEmpty()) {
            // 把当前时间前到达的进程加入就绪队列
            for (Iterator<PCB> it = pending.iterator(); it.hasNext(); ) {
                PCB p = it.next();
                if (p.arrivalTime <= time) {
                    queue.add(p);
                    it.remove();
                }
            }

            // 如果队列为空，表示 CPU 空闲，时间前进
            if (queue.isEmpty()) {
                time++;
                continue;
            }

            // 从队首取出一个进程
            PCB p = queue.remove(0);

            // 实际运行时间为 剩余时间 和 时间片 的较小值
            int run = Math.min(timeSlice, p.burstTime - p.runnedTime);
            p.runnedTime += run;
            time += run; // 时间推进

            // 检查运行过程中是否有新进程到达
            for (Iterator<PCB> it = pending.iterator(); it.hasNext(); ) {
                PCB newp = it.next();
                if (newp.arrivalTime <= time) {
                    queue.add(newp);
                    it.remove();
                }
            }

            // 如果已运行完，记录完成时间；否则重新排队
            if (p.runnedTime == p.burstTime) {
                p.finishedTime = time;
            } else {
                queue.add(p); // 未完成，继续参与轮转
            }
        }

        printResult("RR", processes);
    }

    //  打印调度结果及平均时间
    static void printResult(String title, List<PCB> processes) {
        System.out.println("\n[" + title + "] 调度结果：");
        double totalTurn = 0, totalWeight = 0;

        for (PCB p : processes) {
            int tat = p.getTurnaroundTime();              // 周转时间
            double wtat = p.getWeightedTurnaroundTime();  // 带权周转时间
            System.out.printf("进程 %s: 周转时间=%d, 带权周转时间=%.2f\n",
                    p.name, tat, wtat);
            totalTurn += tat;
            totalWeight += wtat;
        }

        int n = processes.size();
        System.out.printf("平均周转时间：%.2f\n", totalTurn / n);
        System.out.printf("平均带权周转时间：%.2f\n", totalWeight / n);
    }
}
